package com.skq.interceptors;

import com.skq.utils.JwtUtil;
import com.skq.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Map;

/**
 * @author skq
 * @data 2024/6/6
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 在请求处理之前进行 intercept（拦截）。
     * 该方法用于验证请求头中的 Authorization 令牌（token），以确保请求的合法性。
     * 如果 token 验证成功，则允许请求继续处理；如果验证失败，则返回 401 未授权的状态码。
     *
     * @param request  HttpServletRequest 对象，用于获取请求头信息。
     * @param response HttpServletResponse 对象，用于设置响应状态码。
     * @param handler  将要处理请求的具体处理器对象。
     * @return 如果 token 验证成功，返回 true；否则返回 false。
     * @throws Exception 如果在处理过程中发生异常。
     */
    @Override
    //在请求处理之前进行调用（Controller方法调用之前）
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从请求头中获取 Authorization 信息，即 token。
        String token = request.getHeader("Authorization");
        try {
            // 尝试解析 token，如果解析成功，则说明 token 验证通过。
            Map<String, Object> claims = JwtUtil.parseToken(token);

            Integer id = (Integer) claims.get("id");
            // 从Redis中获取对应id的令牌值
            String redisToken = stringRedisTemplate.opsForValue().get(String.valueOf(id));
            // 检查Redis中的令牌是否为空或与传入的令牌不匹配
            if (StringUtils.isBlank(redisToken) || !redisToken.equals(token)) {
                // 如果不匹配，则抛出运行时异常，表示令牌无效或已过期
                throw new RuntimeException();
            }


            //把业务数据存储到ThreadLocal中
            ThreadLocalUtil.set(claims);
            return true;
        } catch (Exception e) {
            // 如果解析 token 发生异常，则说明 token 验证失败，设置响应状态码为 401 未授权，并返回 false。
            response.setStatus(401);
            return false;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //清空ThreadLocal中的数据
        ThreadLocalUtil.remove();
    }
}
